package base_jwt

import (
	"fmt"
	"github.com/golang-jwt/jwt/v4"
	"go.uber.org/zap"
	"time"
)

// CreateToken 创建token
func CreateToken(claims CustomClaims, signingKey string) (string, bool) {
	// 创建 Token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 签名 Token
	tokenStr, err := token.SignedString([]byte(signingKey))

	if err != nil {
		zap.S().Errorw("创建token失败", "errMsg", err.Error())
		return "", false
	}
	return tokenStr, true
}

// ParseToken 解析 JWT Token
func ParseToken(tokenString, signingKey string) (*CustomClaims, error) {
	// 解析 Token
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 确保使用的是 HMAC 加密
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			zap.S().Errorf("无效的签名算法: %v", token.Header["alg"])
			return nil, fmt.Errorf("无效的签名算法: %v", token.Header["alg"])
		}
		return []byte(signingKey), nil
	})

	// 处理解析错误
	if err != nil {
		zap.S().Errorw("token解析错误", "token", tokenString,
			"errorMsg", err.Error())
		return nil, fmt.Errorf("无效Token")
	}

	// 校验 Token 是否有效，并转换为 *MyClaims
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		return claims, nil
	}

	zap.S().Errorw("转换Claims错误=>解析成功token无效", "token", tokenString,
		"errorMsg", err)
	return nil, fmt.Errorf("无效Token")
}

func DefaultRegisteredClaims() jwt.RegisteredClaims {
	// 生成过期时间: 一天后过期
	expirationTime := time.Now().Add(24 * time.Hour)

	// 创建 Claims
	registeredClaims := jwt.RegisteredClaims{
		ExpiresAt: jwt.NewNumericDate(expirationTime), // 过期时间
		//IssuedAt(签发时间): 有些验证策略要求Token只能在签发时间后使用，防止Token伪造。 可以用于防止回放攻击（Replay Attack）。
		IssuedAt: jwt.NewNumericDate(time.Now()),
		//NotBefore(生效时间): Token在此时间之前无法使用（阻止提前使用）; 适用于限制令牌在某个时间点后生效的场景。
		NotBefore: jwt.NewNumericDate(time.Now()),
		//Issuer发行者: Token的签发者（用于多系统验证时区分来源）; 当多个服务占用一个认证系统时，Issuer可用于区分 Token 的签名来源。
		Issuer: "lw",
	}
	return registeredClaims
}

func CustomRegisteredClaims(expirationTime time.Time, issuer string) jwt.RegisteredClaims {
	// 创建 Claims
	registeredClaims := jwt.RegisteredClaims{
		ExpiresAt: jwt.NewNumericDate(expirationTime), // 过期时间
		//IssuedAt(签发时间): 有些验证策略要求Token只能在签发时间后使用，防止Token伪造。 可以用于防止回放攻击（Replay Attack）。
		IssuedAt: jwt.NewNumericDate(time.Now()),
		//NotBefore(生效时间): Token在此时间之前无法使用（阻止提前使用）; 适用于限制令牌在某个时间点后生效的场景。
		NotBefore: jwt.NewNumericDate(time.Now()),
		//Issuer发行者: Token的签发者（用于多系统验证时区分来源）; 当多个服务占用一个认证系统时，Issuer可用于区分 Token 的签名来源。
		Issuer: issuer,
	}
	return registeredClaims
}
